package com.xiyuan.smartutils.template.engine.expression.operator.arithmetic.impl;

import com.xiyuan.smartutils.Types;
import com.xiyuan.smartutils.Validates;
import com.xiyuan.smartutils.template.engine.VariableMap;
import com.xiyuan.smartutils.template.engine.expression.Expression;
import com.xiyuan.smartutils.template.engine.expression.operator.arithmetic._NumOprator;

import java.math.BigDecimal;
import java.math.BigInteger;

/**
 * 求模运算(%)
 * 
 * @version v1.0.0 @author lgz 2020年12月6日 新建与整理
 */
public class _Modulus extends _NumOprator
{
    private static final long serialVersionUID = 1L;
    private final Expression left;
    private final Expression right;
    
    public _Modulus(String path, int line, int column, Expression left, Expression right)
    {
        super(path, line, column);
        this.left = left;
        this.right = right;
        this.assertSymbo("取模", left, right);
    }
    
    @Override
    public int getType()
    {
        return MODULUS;
    }
    
    @Override
    protected Object build(VariableMap variableMap)
    {
        Object prev = left.execute(variableMap);
        Object next = right.execute(variableMap);
        if (prev == null) prev = 0;
        if (next == null) prev = 0;
        checkValue(prev, next, "取模", "左边值", "右边值");
        
        boolean isCharP = Types.isChar(prev);
        boolean isIntegerP = prev != null && Validates.isInteger(String.valueOf(prev));
        boolean isDecimalP = prev != null && Validates.isFloat(String.valueOf(prev));
        
        boolean isCharN = Types.isChar(next);
        boolean isIntegerN = next != null && Validates.isInteger(String.valueOf(next));
        boolean isDecimalN = next != null && Validates.isFloat(String.valueOf(next));
        
        // 字符 - 字符
        // 字符 - 整形
        // 字符 - 小数
        
        // 整形 - 字符
        // 整形 - 整形
        // 整形 - 小数
        
        // 小数 - 小数
        // 小数 - 整形
        // 小数 - 字符
        
        // 字符
        if (isCharP && isCharN) {
            return ((Character) prev) % (((Character) next));
        }
        else if (isCharP && isIntegerN) {
            return returnInteger(BigInteger.valueOf(((int) ((Character) prev))).remainder(parseInteger(next)));
        }
        else if (isCharP && isDecimalN) {

            return returnDecimal(BigDecimal.valueOf(((int) ((Character) prev))).remainder(parseDecimal(next)));
        }
        
        // 整形
        else if (isIntegerP && isCharN) {
            return returnInteger(parseInteger(prev).remainder(BigInteger.valueOf(((int) ((Character) next)))));
        }
        else if (isIntegerP && isIntegerN) {
            return returnInteger(parseInteger(prev).remainder(parseInteger(next)));
        }
        else if (isIntegerP && isDecimalN) {
            return returnDecimal(parseDecimal(prev).remainder(parseDecimal(next)));
        }
        // 小数
        else if (isDecimalP && isCharN) {
            return returnDecimal(parseDecimal(prev).remainder(BigDecimal.valueOf(((int) ((Character) next)))));
        }
        else if (isDecimalP && isIntegerN) {
            return returnDecimal(parseDecimal(prev).remainder(parseDecimal(next)));
        }
        else if (isDecimalP && isDecimalN) {
            return returnDecimal(parseDecimal(prev).remainder(parseDecimal(next)));
        }
        else {
            return 0;
        }
    }
    
    @Override
    public String toString()
    {
        return new StringBuilder().append(left).append(" % ").append(right).toString();
    }
    

}
